﻿using FirstFloor.ModernUI.Windows.Controls;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Serialization;
using EpiNEXT.AttachedCommands;
using EpiNEXT.Core;
using EpiNEXT.Core.Fields;

namespace EpiNEXT.WPF
{
    public class ControlFactory : ControlFactoryBase
    {
        public ControlFactory()
            : base()
        {
            this.BindingMode = BindingMode.TwoWay;
            this.ControlCreationMode = Core.ControlCreationMode.DataEntry;
        }

        public ControlFactory(BindingMode bindingMode = BindingMode.TwoWay, ControlCreationMode creationMode = ControlCreationMode.DataEntry)
            : base(bindingMode, creationMode)
        {
            this.BindingMode = bindingMode;
            this.ControlCreationMode = creationMode;
        }

        protected override List<UIElement> CreateControlsForField(Field field, FormViewModel formVM)
        {
            if (field == null)
            {
                throw new ArgumentNullException("field");
            }

            List<UIElement> controls = new List<UIElement>();

            string fieldType = field.GetType().ToString();
            string currentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture.ToString();
            ICollectionView codeListValuesView = null;

            Binding fieldBinding = new Binding("SelectedForm.RecordsView.CurrentItem." + field.Name);
            fieldBinding.Mode = BindingMode;
            fieldBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            fieldBinding.NotifyOnValidationError = true;
            fieldBinding.ValidatesOnNotifyDataErrors = true;

            Binding enabledBinding = new Binding("SelectedForm.Fields[" + field.Name + "].IsCurrentlyEnabled");
            enabledBinding.Mode = BindingMode.Default;

            Binding inputLeftBinding = new Binding("SelectedForm.Fields[" + field.Name + "].InputLeft");
            Binding inputTopBinding = new Binding("SelectedForm.Fields[" + field.Name + "].InputTop");

            inputLeftBinding.Mode = BindingMode.TwoWay;
            inputTopBinding.Mode = BindingMode.TwoWay;

            FontWeight promptFontWeight = FontWeights.Normal;
            FontWeight inputFontWeight = FontWeights.Normal;

            if (field.PromptFontWeight != null)
            {
                promptFontWeight = GetFontWeightFromString(field.PromptFontWeight);
            }

            if (field is FieldWithSeparatePrompt)
            {
                FieldWithSeparatePrompt fieldWithSeparatePrompt = field as FieldWithSeparatePrompt;
                inputFontWeight = GetFontWeightFromString(fieldWithSeparatePrompt.InputFontWeight);
            }

            switch (fieldType)
            {
                case "EpiNEXT.Core.Fields.LabelField":
                    #region Label Field
                    LabelField labelField = (field as LabelField);
                    Label labelFieldPrompt = new Label();

                    SetPromptProperties(labelFieldPrompt, labelField);

                    labelFieldPrompt.Margin = new Thickness(0);

                    controls.Add(labelFieldPrompt);
                    #endregion // Label Field
                    break;

                case "EpiNEXT.Core.Fields.GroupField":
                    #region Label Field
                    GroupField groupField = (field as GroupField);
                    GroupBox groupBox = new GroupBox();
                    Label header = new Label();

                    Canvas.SetLeft(groupBox, groupField.PromptLeft);
                    Canvas.SetTop(groupBox, groupField.PromptTop);
                    Canvas.SetZIndex(groupBox, -1);

                    SetPromptProperties(header, groupField);

                    header.Margin = new Thickness(0);

                    groupBox.Header = header;

                    groupBox.Width = groupField.Width;
                    groupBox.Height = groupField.Height;

                    controls.Add(groupBox);
                    #endregion // Label Field
                    break;

                case "EpiNEXT.Core.Fields.RelateButtonField":
                case "EpiNEXT.Core.Fields.CommandButtonField":
                    #region Relate Field
                    CommandButtonField buttonField = (field as CommandButtonField);
                    Button button = new Button();
                    Label buttonContent = new Label();

                    SetPromptProperties(buttonContent, buttonField);

                    button.Content = buttonContent;
                    button.HorizontalContentAlignment = HorizontalAlignment.Center;

                    inputLeftBinding = new Binding("SelectedForm.Fields[" + field.Name + "].PromptLeft");
                    inputTopBinding = new Binding("SelectedForm.Fields[" + field.Name + "].PromptTop");

                    inputLeftBinding.Mode = BindingMode.TwoWay;
                    inputTopBinding.Mode = BindingMode.TwoWay;

                    button.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    button.SetBinding(Canvas.TopProperty, inputTopBinding);

                    //Canvas.SetLeft(button, buttonField.PromptLeft);
                    //Canvas.SetTop(button, buttonField.PromptTop);

                    //if (buttonField.PromptWidth != 0)
                    //{
                    //    button.Width = buttonField.PromptWidth;
                    //}
                    //if (buttonField.PromptHeight != 0)
                    //{
                    //    button.Height = buttonField.PromptHeight;
                    //}

                    button.TabIndex = buttonField.TabIndex;
                    button.IsTabStop = buttonField.IsTabStop;
                    //button.BorderThickness = buttonField.PromptBorderThickness;
                    if (buttonField.PromptFontSize.HasValue)
                    {
                        button.FontSize = buttonField.PromptFontSize.Value;
                    }
                    //button.Foreground = new SolidColorBrush(buttonField.PromptForegroundColor);
                    button.Background = new SolidColorBrush(ConvertColor(buttonField.ButtonBackgroundColor));
                    button.BorderBrush = new SolidColorBrush(ConvertColor(buttonField.ButtonBorderColor));
                    button.BorderThickness = ConvertThickness(buttonField.ButtonBorderThickness);

                    CommandBehavior.SetRoutedEventName(button, "Click");
                    if (buttonField is RelateButtonField)
                    {
                        CommandBehavior.SetTheCommandToRun(button, formVM.ProjectVM.GoToFormCommand);
                        CommandBehavior.SetTheCommandParameter(button, (buttonField as RelateButtonField).RelatedFormId);
                    }
                    else
                    {
                        switch (buttonField.Command)
                        {
                            case ButtonCommands.Save:
                                CommandBehavior.SetTheCommandToRun(button, formVM.ProjectVM.SaveRecordAsyncCommand);
                                break;
                            case ButtonCommands.New:
                                CommandBehavior.SetTheCommandToRun(button, formVM.ProjectVM.AddRecordCommand);
                                break;
                            case ButtonCommands.Delete:
                                CommandBehavior.SetTheCommandToRun(button, formVM.ProjectVM.DeleteRecordCommand);
                                break;
                            case ButtonCommands.Execute:
                                CommandBehavior.SetTheCommandToRun(button, formVM.ProjectVM.ExecuteProgramCommand);
                                CommandBehavior.SetTheCommandParameter(button, buttonField.CommandParameter);
                                break;
                        }
                    }
                    
                    button.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(button);
                    #endregion // Relate Field
                    break;

                case "EpiNEXT.Core.Fields.TextBoxField":
                    #region TextBox Field
                    TextBoxField textBoxField = (field as TextBoxField);
                    Label textBoxFieldPrompt = new Label();
                    TextBox textBoxFieldInput = new TextBox();

                    fieldBinding.NotifyOnValidationError = true;
                    fieldBinding.ValidatesOnDataErrors = true;
                    fieldBinding.ValidatesOnNotifyDataErrors = true;
                    textBoxFieldInput.SetBinding(TextBox.TextProperty, fieldBinding);

                    //Canvas.SetLeft(textBoxFieldInput, textBoxField.InputLeft);
                    //Canvas.SetTop(textBoxFieldInput, textBoxField.InputTop);

                    textBoxFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    textBoxFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                    SetPromptProperties(textBoxFieldPrompt, textBoxField);
                    SetInputProperties(textBoxFieldInput, textBoxField);

                    if (!String.IsNullOrEmpty(textBoxField.InputMask))
                    {
                        Behaviors.TextBoxInputMaskBehavior textBoxInputMaskBehavior = new Behaviors.TextBoxInputMaskBehavior();
                        textBoxInputMaskBehavior.InputMask = textBoxField.InputMask;
                        textBoxInputMaskBehavior.PromptChar = '_';
                        System.Windows.Interactivity.Interaction.GetBehaviors(textBoxFieldInput).Add(textBoxInputMaskBehavior);
                    }

                    textBoxFieldInput.Width = textBoxField.InputWidth;
                    textBoxFieldInput.MaxLength = textBoxField.MaxLength;
                    textBoxFieldInput.FontWeight = inputFontWeight;
                    textBoxFieldInput.TabIndex = textBoxField.TabIndex;
                    textBoxFieldInput.IsTabStop = textBoxField.IsTabStop;
                    textBoxFieldInput.BorderThickness = ConvertThickness(textBoxField.InputBorderThickness);
                    textBoxFieldInput.FontSize = textBoxField.InputFontSize;
                    //textBoxFieldInput.Foreground = new SolidColorBrush(textBoxField.InputForegroundColor);
                    //textBoxFieldInput.Background = new SolidColorBrush(textBoxField.InputBackgroundColor);
                    //textBoxFieldInput.BorderBrush = new SolidColorBrush(textBoxField.InputBorderColor);
                    textBoxFieldInput.AcceptsReturn = textBoxField.AcceptsReturn;

                    //textBoxFieldInput.Foreground.Freeze();
                    //textBoxFieldInput.Background.Freeze();
                    //textBoxFieldInput.BorderBrush.Freeze();

                    if (textBoxField.AcceptsReturn)
                    {
                        textBoxFieldInput.Height = textBoxField.InputHeight;
                        textBoxFieldInput.TextWrapping = TextWrapping.WrapWithOverflow;
                    }

                    if (textBoxField.ForceUppercase)
                    {
                        textBoxFieldInput.CharacterCasing = CharacterCasing.Upper;
                    }

                    //if (textBoxField.IsOtherBox)
                    //{
                    textBoxFieldInput.SetBinding(TextBox.IsEnabledProperty, enabledBinding);
                    //}

                    Canvas.SetZIndex(textBoxFieldInput, 2);

                    controls.Add(textBoxFieldPrompt);
                    controls.Add(textBoxFieldInput);

                    #endregion // TextBox Field
                    break;

                case "EpiNEXT.Core.Fields.FixedCellTextBoxField":
                    #region FixedCellTextBox Field
                    FixedCellTextBoxField fcTextBoxField = (field as FixedCellTextBoxField);
                    Label fcTextBoxFieldPrompt = new Label();
                    FixedCellTextBox fcTextBoxFieldInput = new FixedCellTextBox();

                    fieldBinding.NotifyOnValidationError = true;
                    fieldBinding.ValidatesOnDataErrors = true;
                    fieldBinding.ValidatesOnNotifyDataErrors = true;
                    fcTextBoxFieldInput.SetBinding(FixedCellTextBox.ItemsSourceProperty, fieldBinding);

                    Canvas.SetLeft(fcTextBoxFieldInput, fcTextBoxField.InputLeft);
                    Canvas.SetTop(fcTextBoxFieldInput, fcTextBoxField.InputTop);

                    SetPromptProperties(fcTextBoxFieldPrompt, fcTextBoxField);

                    //textBoxFieldInput.FontWeight = inputFontWeight;
                    fcTextBoxFieldInput.TabIndex = fcTextBoxField.TabIndex;
                    fcTextBoxFieldInput.IsTabStop = fcTextBoxField.IsTabStop;
                    //fcTextBoxFieldInput.BorderThickness = textBoxField.InputBorderThickness;
                    //fcTextBoxFieldInput.FontSize = fcTextBoxField.InputFontSize;
                    //fcTextBoxFieldInput.Foreground = new SolidColorBrush(fcTextBoxField.InputForegroundColor);
                    //fcTextBoxFieldInput.Background = new SolidColorBrush(fcTextBoxField.InputBackgroundColor);
                    //fcTextBoxFieldInput.BorderBrush = new SolidColorBrush(fcTextBoxField.InputBorderColor);
                    //fcTextBoxFieldInput.AcceptsReturn = textBoxField.AcceptsReturn;

                    //if (textBoxField.ForceUppercase)
                    //{
                    //    fcTextBoxField.CharacterCasing = CharacterCasing.Upper;
                    //}

                    controls.Add(fcTextBoxFieldPrompt);
                    controls.Add(fcTextBoxFieldInput);

                    #endregion // FixedCellTextBox Field
                    break;

                case "EpiNEXT.Core.Fields.YesNoField":
                    #region YesNo Field
                    YesNoField ynField = (field as YesNoField);
                    Label ynFieldPrompt = new Label();
                    ComboBox ynFieldInput = new ComboBox();
                    ynFieldInput.SetBinding(ComboBox.SelectedValueProperty, fieldBinding);

                    //Canvas.SetLeft(comboBoxFieldInput, comboBoxField.InputLeft);
                    //Canvas.SetTop(comboBoxFieldInput, comboBoxField.InputTop);

                    ynFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    ynFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                    SetPromptProperties(ynFieldPrompt, ynField);

                    CodeListViewModel ynCodeListVM = formVM.GetCodeListViewModelForField(ynField);

                    ynFieldInput.FontWeight = inputFontWeight;

                    SetListControlProperties(ynFieldInput, ynField);
                    SetInputProperties(ynFieldInput, ynField);

                    ynFieldInput.ItemsSource = ynCodeListVM.CodeListValuesView; //codeListVM.CodeListValuesView; //codeListValuesView;
                    ynFieldInput.IsEditable = true;
                    ynFieldInput.IsReadOnly = false;

                    ynFieldInput.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(ynFieldPrompt);
                    controls.Add(ynFieldInput);
                    #endregion // YesNo Field
                    break;

                case "EpiNEXT.Core.Fields.ComboBoxField":
                    #region ComboBox Field
                    ComboBoxField comboBoxField = (field as ComboBoxField);
                    Label comboBoxFieldPrompt = new Label();
                    SetPromptProperties(comboBoxFieldPrompt, comboBoxField);

                    CodeListViewModel codeListVM = formVM.GetCodeListViewModelForField(comboBoxField);

                    if (ControlCreationMode == Core.ControlCreationMode.Printing)
                    {
                        TextBox comboBoxFieldInput = new TextBox();
                        comboBoxFieldInput.SetBinding(TextBox.TextProperty, fieldBinding);

                        comboBoxFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                        comboBoxFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                        comboBoxFieldInput.FontWeight = inputFontWeight;
                        SetInputProperties(comboBoxFieldInput, comboBoxField);

                        comboBoxFieldInput.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                        controls.Add(comboBoxFieldInput);
                    }
                    else
                    {
                        ComboBox comboBoxFieldInput = new ComboBox();
                        comboBoxFieldInput.SetBinding(ComboBox.SelectedValueProperty, fieldBinding);

                        comboBoxFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                        comboBoxFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                        comboBoxFieldInput.FontWeight = inputFontWeight;

                        SetListControlProperties(comboBoxFieldInput, comboBoxField);
                        SetInputProperties(comboBoxFieldInput, comboBoxField);

                        comboBoxFieldInput.ItemsSource = codeListVM.CodeListValuesView; //codeListVM.CodeListValuesView; //codeListValuesView;
                        comboBoxFieldInput.IsEditable = true;
                        comboBoxFieldInput.IsReadOnly = false;

                        CommandBehavior.SetRoutedEventName(comboBoxFieldInput, "SelectionChanged");
                        CommandBehavior.SetTheCommandToRun(comboBoxFieldInput, formVM.ProjectVM.UpdateComboBoxFilterCommand);
                        CommandBehavior.SetTheCommandParameter(comboBoxFieldInput, comboBoxField);

                        if (codeListVM.Mode == CodeListMode.CodedCascadeToDestination)
                        {
                            CommandBehavior.SetRoutedEventName(comboBoxFieldInput, "SelectionChanged");
                            CommandBehavior.SetTheCommandToRun(comboBoxFieldInput, formVM.ProjectVM.UpdateComboBoxTargetsCommand);
                            CommandBehavior.SetTheCommandParameter(comboBoxFieldInput, comboBoxField);
                        }

                        comboBoxFieldInput.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                        controls.Add(comboBoxFieldInput);
                    }
                    controls.Add(comboBoxFieldPrompt);
                    #endregion // ComboBox Field
                    break;

                case "EpiNEXT.Core.Fields.RadioButtonListField":
                case "EpiNEXT.Core.Fields.CheckBoxListField":
                    #region RadioButton Field
                    OrientableListSelectorField radioButtonListField = (field as OrientableListSelectorField);
                    Label radioButtonListPrompt = new Label();
                    OrientableListSelector radioButtonList = null;

                    if (field is CheckBoxListField)
                    {
                        radioButtonList = new CheckBoxList();
                        radioButtonList.Style = radioButtonList.TryFindResource("CheckBoxListBoxStyle") as Style;
                    }
                    else
                    {
                        radioButtonList = new RadioButtonList();
                        radioButtonList.Style = radioButtonList.TryFindResource("RadioButtonListBoxStyle") as Style;
                    }

                    radioButtonList.Orientation = radioButtonListField.Orientation;
                    radioButtonList.SetBinding(ComboBox.SelectedValueProperty, fieldBinding);

                    //Canvas.SetLeft(radioButtonList, radioButtonListField.InputLeft);
                    //Canvas.SetTop(radioButtonList, radioButtonListField.InputTop);

                    radioButtonList.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    radioButtonList.SetBinding(Canvas.TopProperty, inputTopBinding);

                    SetPromptProperties(radioButtonListPrompt, radioButtonListField);
                    SetInputProperties(radioButtonList, radioButtonListField);

                    CodeListViewModel radioCodeListVM = formVM.GetCodeListViewModelForField(radioButtonListField);

                    radioButtonList.FontWeight = inputFontWeight;

                    SetListControlProperties(radioButtonList, radioButtonListField);

                    radioButtonList.ItemsSource = radioCodeListVM.CodeListValuesView; //codeListVM.CodeListValuesView; //codeListValuesView;

                    CommandBehavior.SetRoutedEventName(radioButtonList, "SelectionChanged");
                    CommandBehavior.SetTheCommandToRun(radioButtonList, formVM.ProjectVM.UpdateComboBoxFilterCommand);
                    CommandBehavior.SetTheCommandParameter(radioButtonList, radioButtonListField);

                    if (radioCodeListVM.Mode == CodeListMode.CodedCascadeToDestination)
                    {
                        CommandBehavior.SetRoutedEventName(radioButtonList, "SelectionChanged");
                        CommandBehavior.SetTheCommandToRun(radioButtonList, formVM.ProjectVM.UpdateComboBoxTargetsCommand);
                        CommandBehavior.SetTheCommandParameter(radioButtonList, radioButtonListField);
                    }

                    Canvas.SetZIndex(radioButtonList, 1);

                    radioButtonList.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    radioButtonList.BorderThickness = new Thickness(0, 0, 0, 0);

                    controls.Add(radioButtonListPrompt);
                    controls.Add(radioButtonList);
                    #endregion // RadioButton Field
                    break;

                case "EpiNEXT.Core.Fields.ListBoxField":
                    #region ComboBox Field
                    ListBoxField listBoxField = (field as ListBoxField);
                    Label listBoxFieldPrompt = new Label();
                    ListBox listBoxFieldInput = new ListBox();
                    listBoxFieldInput.SetBinding(ListBox.SelectedValueProperty, fieldBinding);

                    //Canvas.SetLeft(listBoxFieldInput, listBoxField.InputLeft);
                    //Canvas.SetTop(listBoxFieldInput, listBoxField.InputTop);
                    listBoxFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    listBoxFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                    SetPromptProperties(listBoxFieldPrompt, listBoxField);
                    SetInputProperties(listBoxFieldInput, listBoxField);

                    // TODO: Move to view model
                    codeListValuesView = new CollectionViewSource { Source = listBoxField.ListSource.CodeListValues }.View;
                    codeListValuesView.Filter = new Predicate<object>
                    (
                            listValue =>
                                ((CodeListValue)listValue).Culture == null ||
                                String.IsNullOrEmpty(((CodeListValue)listValue).Culture) || 
                                ((CodeListValue)listValue).Culture == currentUICulture
                    );

                    listBoxFieldInput.FontWeight = inputFontWeight;

                    SetListControlProperties(listBoxFieldInput, listBoxField);

                    //listBoxFieldInput.TabIndex = listBoxField.TabIndex;
                    //listBoxFieldInput.IsTabStop = listBoxField.IsTabStop;
                    //listBoxFieldInput.Width = listBoxField.InputWidth;
                    //listBoxFieldInput.Height = listBoxField.InputHeight;
                    //listBoxFieldInput.DisplayMemberPath = "DisplayUI";
                    //listBoxFieldInput.SelectedValuePath = "Store";
                    listBoxFieldInput.ItemsSource = codeListValuesView;
                    listBoxFieldInput.SelectionMode = SelectionMode.Single;
                    //listBoxFieldInput.BorderThickness = listBoxField.InputBorderThickness;
                    //listBoxFieldInput.FontSize = listBoxField.InputFontSize;
                    //listBoxFieldInput.Foreground = new SolidColorBrush(listBoxField.InputForegroundColor);
                    //listBoxFieldInput.Background = new SolidColorBrush(listBoxField.InputBackgroundColor);
                    //listBoxFieldInput.BorderBrush = new SolidColorBrush(listBoxField.InputBorderColor);
                    //listBoxFieldInput.IsSynchronizedWithCurrentItem = true;
                    listBoxFieldInput.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(listBoxFieldPrompt);
                    controls.Add(listBoxFieldInput);
                    #endregion // ComboBox Field
                    break;

                case "EpiNEXT.Core.Fields.ImageField":
                    #region Image Field
                    ImageField imageField = (field as ImageField);
                    Label imagePrompt = new Label();
                    ImagePicker image = new ImagePicker();
                    fieldBinding.Converter = image.TryFindResource("ByteArrayToImageConverter") as IValueConverter;
                    image.SetBinding(ImagePicker.SourceProperty, fieldBinding);

                    if (ControlCreationMode == ControlCreationMode.Printing)
                    {
                        image.IsHitTestVisible = false;
                    }

                    //Canvas.SetLeft(image, imageField.InputLeft);
                    //Canvas.SetTop(image, imageField.InputTop);
                    image.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    image.SetBinding(Canvas.TopProperty, inputTopBinding);

                    image.ImageHeight = imageField.InputHeight;
                    image.ImageWidth = imageField.InputWidth;

                    image.TabIndex = imageField.TabIndex;
                    image.IsTabStop = imageField.IsTabStop;

                    image.BorderThickness = ConvertThickness(imageField.InputBorderThickness);
                    image.BorderBrush = new SolidColorBrush(ConvertColor(imageField.BorderColor));
                    image.BorderBrush.Freeze();

                    SetPromptProperties(imagePrompt, imageField);

                    image.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(imagePrompt);
                    controls.Add(image);
                    #endregion // ComboBox Field
                    break;

                case "EpiNEXT.Core.Fields.DatePickerField":
                    #region Date Picker
                    DatePickerField dateField = (field as DatePickerField);

                    Label dateFieldPrompt = new Label();
                    DatePicker dateFieldInput = new DatePicker();
                    TextBox tbox = new TextBox();

                    if (ControlCreationMode == Core.ControlCreationMode.DataEntry)
                    {
                        fieldBinding.NotifyOnValidationError = true;
                        fieldBinding.ValidatesOnDataErrors = true;
                        fieldBinding.ValidatesOnNotifyDataErrors = true;
                        dateFieldInput.SetBinding(DatePicker.SelectedDateProperty, fieldBinding);

                        // secondary binding, for when the user types in a value
                        Binding dateFieldBinding = new Binding("CurrentItem." + field.Name);
                        dateFieldBinding.Mode = BindingMode.TwoWay;
                        dateFieldBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                        dateFieldInput.SetBinding(DatePicker.DisplayDateProperty, dateFieldBinding);

                        if (dateField.LowerBound.HasValue)
                        {
                            DateTime lowerBound = new DateTime(dateField.LowerBound.Value);
                            dateFieldInput.DisplayDateStart = lowerBound;
                        }
                        if (dateField.UpperBound.HasValue)
                        {
                            DateTime upperBound = new DateTime(dateField.UpperBound.Value);
                            dateFieldInput.DisplayDateEnd = upperBound;
                        }
                    }
                    else if (ControlCreationMode == Core.ControlCreationMode.Printing)
                    {
                        fieldBinding.StringFormat = System.Threading.Thread.CurrentThread.CurrentUICulture.DateTimeFormat.ShortDatePattern;// "d/M/yy";
                        tbox.SetBinding(TextBox.TextProperty, fieldBinding);
                        tbox.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                        tbox.SetBinding(Canvas.TopProperty, inputTopBinding);

                        tbox.Width = dateField.InputWidth;
                        tbox.FontWeight = inputFontWeight;
                        tbox.TabIndex = dateField.TabIndex;
                        tbox.IsTabStop = dateField.IsTabStop;
                        tbox.BorderThickness = ConvertThickness(dateField.InputBorderThickness);
                        tbox.FontSize = dateField.InputFontSize;
                        tbox.SetBinding(TextBox.IsEnabledProperty, enabledBinding);
                    }
                    dateFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    dateFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                    SetPromptProperties(dateFieldPrompt, dateField);
                    SetInputProperties(dateFieldInput, dateField);

                    dateFieldInput.Width = dateField.InputWidth;
                    dateFieldInput.FontWeight = inputFontWeight;
                    dateFieldInput.TabIndex = dateField.TabIndex;
                    dateFieldInput.IsTabStop = dateField.IsTabStop;
                    dateFieldInput.BorderThickness = ConvertThickness(dateField.InputBorderThickness);
                    dateFieldInput.FontSize = dateField.InputFontSize;

                    dateFieldInput.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(dateFieldPrompt);
                    if (ControlCreationMode == Core.ControlCreationMode.Printing)
                    {
                        controls.Add(tbox);
                    }
                    else
                    {
                        controls.Add(dateFieldInput);
                    }
                    #endregion // Date Picker
                    break;

                case "EpiNEXT.Core.Fields.DateBoxField":
                    #region Date Picker
                    DateBoxField dateBoxField = (field as DateBoxField);

                    Label dateBoxFieldPrompt = new Label();
                    TextBox dateBoxFieldInput = new TextBox();

                    fieldBinding.NotifyOnValidationError = true;
                    fieldBinding.ValidatesOnDataErrors = true;
                    fieldBinding.ValidatesOnNotifyDataErrors = true;
                    fieldBinding.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus;
                    dateBoxFieldInput.SetBinding(TextBox.TextProperty, fieldBinding);

                    if (!String.IsNullOrEmpty(dateBoxField.InputMask))
                    {
                        Behaviors.TextBoxInputMaskBehavior textBoxInputMaskBehavior = new Behaviors.TextBoxInputMaskBehavior();
                        textBoxInputMaskBehavior.InputMask = dateBoxField.InputMask;
                        textBoxInputMaskBehavior.PromptChar = '_';
                        System.Windows.Interactivity.Interaction.GetBehaviors(dateBoxFieldInput).Add(textBoxInputMaskBehavior);
                    }

                    dateBoxFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    dateBoxFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                    SetPromptProperties(dateBoxFieldPrompt, dateBoxField);
                    SetInputProperties(dateBoxFieldInput, dateBoxField);

                    dateBoxFieldInput.Width = dateBoxField.InputWidth;
                    dateBoxFieldInput.FontWeight = inputFontWeight;
                    dateBoxFieldInput.TabIndex = dateBoxField.TabIndex;
                    dateBoxFieldInput.IsTabStop = dateBoxField.IsTabStop;
                    dateBoxFieldInput.BorderThickness = ConvertThickness(dateBoxField.InputBorderThickness);
                    dateBoxFieldInput.FontSize = dateBoxField.InputFontSize;

                    dateBoxFieldInput.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(dateBoxFieldPrompt);
                    controls.Add(dateBoxFieldInput);
                    #endregion // Date Picker
                    break;

                case "EpiNEXT.Core.Fields.NumberField":
                    #region Number Field
                    NumberField numberBoxField = (field as NumberField);

                    Label numberFieldPrompt = new Label();
                    TextBox numberFieldInput = new TextBox();

                    fieldBinding.NotifyOnValidationError = true;
                    fieldBinding.ValidatesOnDataErrors = true;
                    fieldBinding.ValidatesOnNotifyDataErrors = true;

                    numberFieldInput.SetBinding(TextBox.TextProperty, fieldBinding);

                    //Canvas.SetLeft(numberFieldInput, numberBoxField.InputLeft);
                    //Canvas.SetTop(numberFieldInput, numberBoxField.InputTop);
                    numberFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    numberFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                    SetPromptProperties(numberFieldPrompt, numberBoxField);
                    SetInputProperties(numberFieldInput, numberBoxField);

                    numberFieldInput.FontWeight = inputFontWeight;
                    numberFieldInput.Width = numberBoxField.InputWidth;
                    numberFieldInput.TabIndex = numberBoxField.TabIndex;
                    numberFieldInput.IsTabStop = numberBoxField.IsTabStop;
                    numberFieldInput.BorderThickness = ConvertThickness(numberBoxField.InputBorderThickness);
                    numberFieldInput.FontSize = numberBoxField.InputFontSize;
                    //numberFieldInput.Foreground = new SolidColorBrush(numberBoxField.InputForegroundColor);
                    //numberFieldInput.Background = new SolidColorBrush(numberBoxField.InputBackgroundColor);
                    //numberFieldInput.BorderBrush = new SolidColorBrush(numberBoxField.InputBorderColor);

                    //numberFieldInput.Foreground.Freeze();
                    //numberFieldInput.Background.Freeze();
                    //numberFieldInput.BorderBrush.Freeze();

                    numberFieldInput.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(numberFieldPrompt);
                    controls.Add(numberFieldInput);
                    #endregion // Number Field
                    break;

                case "EpiNEXT.Core.Fields.CheckBoxField":
                    #region Checkbox
                    CheckBoxField checkBoxField = (field as CheckBoxField);

                    CheckBox checkBoxFieldInput = new CheckBox();

                    checkBoxFieldInput.SetBinding(CheckBox.IsCheckedProperty, fieldBinding);

                    //Canvas.SetLeft(checkBoxFieldInput, checkBoxField.InputLeft);
                    //Canvas.SetTop(checkBoxFieldInput, checkBoxField.InputTop);
                    checkBoxFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    checkBoxFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                    checkBoxFieldInput.Content = checkBoxField.PromptText;
                    checkBoxFieldInput.FontWeight = promptFontWeight;
                    checkBoxFieldInput.IsThreeState = checkBoxField.IsThreeState;
                    checkBoxFieldInput.TabIndex = checkBoxField.TabIndex;
                    checkBoxFieldInput.IsTabStop = checkBoxField.IsTabStop;
                    if (checkBoxField.PromptFontSize.HasValue)
                    {
                        checkBoxFieldInput.FontSize = checkBoxField.PromptFontSize.Value;
                    }

                    checkBoxFieldInput.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(checkBoxFieldInput);
                    #endregion // Checkbox
                    break;

                case "EpiNEXT.Core.Fields.MirrorField":
                    #region Mirror Field
                    MirrorField mirrorField = (field as MirrorField);

                    TextBox mirrorFieldInput = new TextBox();

                    Binding mirrorFieldBinding = new Binding("SelectedForm.RecordsView.CurrentItem." + mirrorField.FieldToMirror.Name);
                    mirrorFieldBinding.Mode = BindingMode.TwoWay;
                    mirrorFieldBinding.NotifyOnSourceUpdated = true;
                    mirrorFieldBinding.NotifyOnTargetUpdated = true;
                    mirrorFieldBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

                    if (ControlCreationMode != Core.ControlCreationMode.Design)
                    {
                        mirrorFieldInput.SetBinding(TextBox.TextProperty, mirrorFieldBinding);
                    }

                    mirrorFieldInput.IsReadOnly = mirrorField.IsReadOnly;
                    mirrorFieldInput.Width = mirrorField.InputWidth;
                    mirrorFieldInput.IsTabStop = false;

                    SetInputProperties(mirrorFieldInput, mirrorField);

                    //Canvas.SetLeft(mirrorFieldInput, mirrorField.InputLeft);
                    //Canvas.SetTop(mirrorFieldInput, mirrorField.InputTop);
                    mirrorFieldInput.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    mirrorFieldInput.SetBinding(Canvas.TopProperty, inputTopBinding);

                    mirrorFieldInput.FontWeight = inputFontWeight;
                    mirrorFieldInput.FontSize = mirrorField.InputFontSize;

                    controls.Add(mirrorFieldInput);
                    #endregion // Mirror Field
                    break;

                case "EpiNEXT.Core.Fields.RectangleField":
                    #region Rectangle Field
                    RectangleField rectangleField = (field as RectangleField);

                    Rectangle rectangle = new Rectangle();

                    //Canvas.SetLeft(rectangle, rectangleField.InputLeft);
                    //Canvas.SetTop(rectangle, rectangleField.InputTop);
                    rectangle.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    rectangle.SetBinding(Canvas.TopProperty, inputTopBinding);

                    rectangle.Height = rectangleField.Height;
                    rectangle.Width = rectangleField.Width;
                    rectangle.RadiusX = rectangleField.RadiusX;
                    rectangle.RadiusY = rectangleField.RadiusY;
                    rectangle.Stroke = new SolidColorBrush(ConvertColor(rectangleField.Stroke));
                    rectangle.Fill = new SolidColorBrush(ConvertColor(rectangleField.Fill));
                    rectangle.StrokeThickness = rectangleField.StrokeThickness;
                    rectangle.StrokeThickness = rectangleField.StrokeThickness;

                    if(!String.IsNullOrEmpty(rectangleField.StrokeDashArray)) 
                    {
                        rectangle.StrokeDashArray = new DoubleCollection();
                        string[] doubles = rectangleField.StrokeDashArray.Split(' ');

                        foreach (string d in doubles)
                        {
                            double value;
                            bool success = Double.TryParse(d, out value);
                            if (success)
                            {
                                rectangle.StrokeDashArray.Add(value);
                            }
                        }
                    }

                    rectangle.Stroke.Freeze();
                    rectangle.Fill.Freeze();

                    controls.Add(rectangle);
                    #endregion // Rectangle Field
                    break;

                case "EpiNEXT.Core.Fields.StaticImageField":
                    #region Static image field
                    StaticImageField staticImageField = field as StaticImageField;

                    Image staticImage = new Image();

                    //Canvas.SetLeft(staticImage, staticImageField.InputLeft);
                    //Canvas.SetTop(staticImage, staticImageField.InputTop);
                    staticImage.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    staticImage.SetBinding(Canvas.TopProperty, inputTopBinding);

                    staticImage.Height = staticImageField.Height;
                    staticImage.Width = staticImageField.Width;
                    staticImage.SnapsToDevicePixels = true;

                    Binding staticImageBinding = new Binding("SelectedForm.Fields[" + field.Name + "].ImageBytes");
                    staticImageBinding.Mode = System.Windows.Data.BindingMode.OneTime;
                    staticImageBinding.UpdateSourceTrigger = UpdateSourceTrigger.Default;
                    staticImageBinding.Converter = staticImage.TryFindResource("ByteArrayToImageConverter") as IValueConverter;

                    staticImage.SetBinding(Image.SourceProperty, staticImageBinding);
                    //staticImage.Source = staticImageField.Image;
                    controls.Add(staticImage);
                    #endregion // Static image field
                    break;

                case "EpiNEXT.Core.Fields.DataGridField":
                    #region Static image field
                    DataGridField dataGridField = field as DataGridField;
                    Label dataGridPrompt = new Label();

                    DataGrid dataGrid = new DataGrid();

                    SetPromptProperties(dataGridPrompt, dataGridField);

                    //Canvas.SetLeft(dataGrid, dataGridField.InputLeft);
                    //Canvas.SetTop(dataGrid, dataGridField.InputTop);
                    dataGrid.SetBinding(Canvas.LeftProperty, inputLeftBinding);
                    dataGrid.SetBinding(Canvas.TopProperty, inputTopBinding);

                    dataGrid.Height = dataGridField.InputHeight;
                    dataGrid.Width = dataGridField.InputWidth;
                    dataGrid.AutoGenerateColumns = false;

                    DataGridTableViewModel tableVM = formVM.ProjectVM.GetDataGridTableById(dataGridField.DataGridTableId);
                    
                    dataGrid.ItemsSource = tableVM.RecordsView;
                    

                    foreach (Field column in tableVM.Fields)
                    {
                        if (column is TextBoxField)
                        {
                            FirstFloor.ModernUI.Windows.Controls.DataGridTextColumn dgColumn = new FirstFloor.ModernUI.Windows.Controls.DataGridTextColumn();

                            Binding columnBinding = new Binding(column.Name);
                            columnBinding.Mode = BindingMode.TwoWay;
                            columnBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                            dgColumn.Binding = columnBinding;
                            dgColumn.Header = column.Name;

                            dataGrid.Columns.Add(dgColumn);
                        }
                    }

                    dataGrid.SetBinding(UIElement.IsEnabledProperty, enabledBinding);

                    controls.Add(dataGrid);
                    controls.Add(dataGridPrompt);
                    #endregion // Static image field
                    break;
            }

            return controls;
        }
    }
}
